package edu.spsu.courses;

import java.io.IOException;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.StringTokenizer;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;
import org.htmlcleaner.XPatherException;

import android.os.Handler;
import android.text.Html;
import android.util.Log;

public class AsynchronousSender extends Thread {
	
	private final String TAG = "AsynchronousSender";
	private static final DefaultHttpClient httpClient = new DefaultHttpClient();
	private HttpUriRequest request;
	private Handler handler;
	private CallbackWrapper wrapper;
	
	protected AsynchronousSender(HttpUriRequest request, Handler handler, CallbackWrapper wrapper) {
		this.request=request;
		this.handler=handler;
		this.wrapper=wrapper;
	}
	
	public void run() {
		try {
			final HttpResponse response;
			synchronized(httpClient) {
				response = getClient().execute(request);
			}
			
			Log.d(TAG,"Received a Response to our activity.");
			BasicResponseHandler responseHandler = new BasicResponseHandler();
			String responseString=null;
			try {
				responseString = responseHandler.handleResponse(response);
				Log.d(TAG,"Response size="+responseString.length());
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			ArrayList<Course> classList=null;
			
			
			//Clean the HTML up
			
			HtmlCleaner pageParser = new HtmlCleaner();
			CleanerProperties props = pageParser.getProperties();
			props.setAllowHtmlInsideAttributes(true);
			props.setAllowMultiWordAttributes(true);
			props.setRecognizeUnicodeChars(true);
			props.setOmitComments(true);
			
			TagNode node = pageParser.clean(responseString);
						
			String xPathExpression = "//table//tr";
			try {
				Object[] downloadNodes = node.evaluateXPath(xPathExpression);
				classList = new ArrayList<Course>(downloadNodes.length);	
				
				for(Object linkNode : downloadNodes) {
					String number = pageParser.getInnerHtml(((TagNode)linkNode).getChildTags()[0]);
					if(number!=null) {
						number = number.trim();
					}
					String name = pageParser.getInnerHtml(((TagNode)linkNode).getChildTags()[1]);
					if(name!=null) {
						//Dirty name.  Parse stuff off.
						Log.d(TAG,"Name="+name);
						StringTokenizer tokenizer = new StringTokenizer(name,">");
						tokenizer.nextToken(); //get rid of preceding <nobr
						name = tokenizer.nextToken(); //Should be course name but with </nobr at the end
						tokenizer = new StringTokenizer(name,"<");
						name = tokenizer.nextToken().trim(); //Should be clean name now.
					}
					String title = pageParser.getInnerHtml(((TagNode)linkNode).getChildTags()[2]);
					if(title!=null) {
						title=Html.fromHtml(title).toString();
						title = title.trim();
					}
					String hours = pageParser.getInnerHtml(((TagNode)linkNode).getChildTags()[3]);
					if(hours!=null) {
						hours = hours.trim();
					}
					String days = pageParser.getInnerHtml(((TagNode)linkNode).getChildTags()[4]);
					if(days!=null) {
						days = days.trim();
					}
					String weeks = pageParser.getInnerHtml(((TagNode)linkNode).getChildTags()[5]);
					if(weeks!=null) {
						weeks = weeks.trim();
					}
					String time = pageParser.getInnerHtml(((TagNode)linkNode).getChildTags()[6]);
					if(time!=null) {
						time = time.trim();
					}
					String instructor = pageParser.getInnerHtml(((TagNode)linkNode).getChildTags()[7]);
					if(instructor!=null) {
						instructor = instructor.trim();
					}
					String location = pageParser.getInnerHtml(((TagNode)linkNode).getChildTags()[8]);
					if(location!=null) {
						location = location.trim();
					}
					String studentCount = pageParser.getInnerHtml(((TagNode)linkNode).getChildTags()[9]);
					if(studentCount!=null) {
						studentCount = Html.fromHtml(studentCount).toString();
						studentCount = studentCount.trim();
					}
					Course newCourse = new Course(number, name, title, hours, days, weeks, time, instructor, location, studentCount);
					classList.add(newCourse);
//					++count;
				}
			} catch (XPatherException e) {
				e.printStackTrace();
			}
						
			wrapper.setResponse(classList);
			handler.post(wrapper);
			
		} catch(ClientProtocolException e) {
			e.printStackTrace();
		} catch(IOException e) {
			e.printStackTrace();
		}
		
	}
	
	private HttpClient getClient() {
		try {
			KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
			trustStore.load(null,null);
			
			SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
			sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
			
			HttpParams params = new BasicHttpParams();
			HttpProtocolParams.setVersion(params,  HttpVersion.HTTP_1_1);
			HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
			
			SchemeRegistry registry = new SchemeRegistry();
			registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
			registry.register(new Scheme("https", sf, 443));
			
			ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
			return new DefaultHttpClient(ccm,params);
		} catch (Exception e) {
			return new DefaultHttpClient();
		}
	}
}